package com.mangatta.ec2.service;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.Log;
import com.amazonaws.auth.AWSCredentials;
import com.mangatta.cloud.dao.InstanceDetailDao;
import com.mangatta.cloud.ec2.Ec2Instance;
import com.mangatta.ec2.activity.AlertNotificationActivity;
import com.mangatta.ec2.monitor.Ec2Monitor;
import com.mangatta.ec2.monitor.InstanceListMonitor;
import com.mangatta.ec2.util.StringHelper;
import com.mangatta.ec2.util.Util;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class Ec2DataPullerService extends Service implements OnSharedPreferenceChangeListener {
    private final static String TAG = Ec2DataPullerService.class.getSimpleName();

    private boolean shouldPullData;
    private long pullInterval;
    private InstanceDetailPuller dataPuller;
    private InstanceListPuller instanceListPuller;

    SharedPreferences preferences;

    public long getPullInterval() {
        return pullInterval;
    }

    public void setPullInterval(long pullInterval) {
        this.pullInterval = pullInterval;
    }

    public boolean isShouldPullData() {
        return shouldPullData;
    }

    public void setShouldPullData(boolean shouldPullData) {
        this.shouldPullData = shouldPullData;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        this.shouldPullData = false;
        Log.d(TAG, "onDestroyed");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        this.shouldPullData = Util.isPullEnabled(getApplication());
        this.pullInterval = Util.getPullIntervalInSeconds(getApplication());

        if (!this.dataPuller.isAlive()) {
            this.dataPuller.start();
        }
        if (!this.instanceListPuller.isAlive()) {
            this.instanceListPuller.start();
        }
        Log.d(TAG, "onStarted");
        return START_STICKY;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        //  Setup preferences
        preferences = PreferenceManager.getDefaultSharedPreferences(this);
        preferences.registerOnSharedPreferenceChangeListener(this);
        this.dataPuller = new InstanceDetailPuller();
        this.instanceListPuller = new InstanceListPuller();
        Log.d(TAG, "onCreated");
    }

    public IBinder onBind(Intent intent) {
        return null;
    }

    private class InstanceListPuller extends Thread {
        private InstanceListMonitor instanceListMonitor = null;
        private static final int INSTANCE_MONITOR_INTERVAL_IN_MINUTES = 60;

        public InstanceListPuller() {
            AWSCredentials awsCredentials = Util.getAWSCredentails(getApplication());
            if (awsCredentials != null) {
                instanceListMonitor = new InstanceListMonitor(awsCredentials);
            }
        }

        @Override
        public void run() {
            super.run();
            Ec2DataPullerService ec2DataPullerService = Ec2DataPullerService.this;
            InstanceDetailDao instanceDetail = new InstanceDetailDao(ec2DataPullerService);

            for (; ; ) {
                if (ec2DataPullerService.isShouldPullData() && instanceListMonitor != null) {
                    Log.d(TAG, "Running background thread to pull instance list");
                    try {
                        List<Ec2Instance> ec2Instances = instanceListMonitor.getInstancesDetail();
                        instanceDetail.persistInstanceDetail(ec2Instances);
                        Log.d(TAG, "Instance list pulled from EC2");

                        // Start pulling data for the instances immediately
                        if (!ec2DataPullerService.dataPuller.isAlive()) {
                            ec2DataPullerService.dataPuller.start();
                            Log.d(TAG, "DataPuller thread started");
                        }
                    } catch (Exception e) {
                        Log.e(TAG, "Exception occurred when fetching instance list", e);
                    }
                }
                try {
                    Thread.sleep(INSTANCE_MONITOR_INTERVAL_IN_MINUTES * 1000);
                } catch (InterruptedException e) {
                    ec2DataPullerService.setShouldPullData(false);
                }
            }
        }

        public void updateCredentials() {
            instanceListMonitor = new InstanceListMonitor(Util.getAWSCredentails(getApplication()));
        }
    }

    // This class provides a thread which constantly pulls data from EC2
    private class InstanceDetailPuller extends Thread {
        private Ec2Monitor ec2Monitor = null;

        public InstanceDetailPuller() {
            ec2Monitor = new Ec2Monitor(getApplicationContext());
        }

        /**
         * Update ec2Monitor with new credentials.
         */
        public void updateCredentials() {
            ec2Monitor.updateAWSCredentials();
        }

        @Override
        public void run() {
            super.run();

            Ec2DataPullerService ec2DataPullerService = Ec2DataPullerService.this;

            for (; ; ) {
                if (ec2DataPullerService.isShouldPullData()) {
                    Log.d(TAG, "Running background thread to pull instance data");

                    Map<Ec2Instance, String> unhealthyInstances = ec2Monitor.checkMetricHealth();
                    if (unhealthyInstances != null && !unhealthyInstances.isEmpty()) {
                        Log.d(TAG, "Alarming condition detected on an instance");

                        // Notify user about the Alarm via Status bar notification
                        String notifyString = Context.NOTIFICATION_SERVICE;
                        NotificationManager notificationManager = (NotificationManager) getSystemService(notifyString);

                        int icon = android.R.drawable.ic_dialog_alert;
                        CharSequence tickerText = "Unhealthy EC2 instance(s)";
                        long when = System.currentTimeMillis();
                        Notification notification = new Notification(icon, tickerText, when);

                        ArrayList<String> instanceIds = new ArrayList<String>();
                        ArrayList<String> metrics = new ArrayList<String>();
                        for (Map.Entry<Ec2Instance, String> unhealthyInstance : unhealthyInstances.entrySet()) {
                            instanceIds.add(unhealthyInstance.getKey().getInstanceId());
                            metrics.add(unhealthyInstance.getValue());
                        }
                        CharSequence contentTitle = "Unhealthy EC2 instance(s)";
                        CharSequence contentText = StringHelper.join(instanceIds, ", ");
                        Intent notificationIntent = new Intent(ec2DataPullerService, AlertNotificationActivity.class);

                        notificationIntent.putStringArrayListExtra("InstanceIds", instanceIds);
                        notificationIntent.putStringArrayListExtra("Metrics", metrics);

                        PendingIntent contentIntent = PendingIntent.getActivity(ec2DataPullerService, 0, notificationIntent, 0);
                        notification.setLatestEventInfo(ec2DataPullerService, contentTitle, contentText, contentIntent);
                        notification.defaults |= Notification.DEFAULT_ALL;
                        notificationManager.notify(1, notification);
                    }
                    Log.d(TAG, "Instance data pulled from EC2");
                }
                try {
                    Thread.sleep(ec2DataPullerService.getPullInterval() * 1000);
                } catch (InterruptedException e) {
                    ec2DataPullerService.setShouldPullData(false);
                } catch(Exception e){
                	Log.e(TAG, "Got exception in instance detail puller",e);
                }
            }
        }
    }

    public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
        if (key == null) {
            return;
        }

        if (Util.isAwsCredentialKey(key) && Util.isAWSCredentialsAvailable(this)) {
            dataPuller.updateCredentials();
            instanceListPuller.updateCredentials();
        }

        if (key.equals(Util.PULL_INTERVAL_IN_SECONDS)) {
            int timeInterval = Util.DEFAULT_PULL_INTERVAL_IN_SECONDS;
            try {
                timeInterval = Integer.parseInt(prefs.getString(Util.PULL_INTERVAL_IN_SECONDS, null));
            } catch (Exception e) {
                Log.d(TAG, "Pull interval is invalid", e);
            }
            setPullInterval(timeInterval);
        }

        if (key.equals(Util.PULL_ENABLED)) {
            setShouldPullData(prefs.getBoolean(Util.PULL_ENABLED, true));
        }
    }
}
